<?php

namespace app\common\library;

use app\common\library\Exception;
use think\Config;
use fast\Random;
use app\common\model\Attachment;

/**
 * 下载远程图片
 */
class DownloadRemoteImage
{

    public $typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3];

    /**
     * 下载远程图片
     * 
     * @param int       $userID     用户ID
     * @param string    $imageUrl   图片URL
     * @return string   返回图片下载后的路径
     */
    public function download($userID, $imageUrl)
    {
        if (empty($imageUrl)) {
            new Exception('Image url cannot empty');
        } else if ($userID) {
            new Exception('User ID cannot empty');
        }

        // 获取图片头信息
        \think\Log::record('$imageUrl##' . $imageUrl);
        $imgaeHeaderData = $this->getImageHeaderData($imageUrl);
        // 获取图片名称
        $imgaeHeaderData['name'] = $this->getImageName($imageUrl);

        $suffix = strtolower(pathinfo($imgaeHeaderData['name'], PATHINFO_EXTENSION));
        $suffix = $suffix && preg_match("/^[a-zA-Z0-9]+$/", $suffix) ? $suffix : 'file';

        // 获取上传配置项
        $upload = Config::get('upload');

        preg_match('/(\d+)(\w+)/', $upload['maxsize'], $matches);
        $type = strtolower($matches[2]);
        $size = (int) $upload['maxsize'] * pow(1024, isset($this->typeDict[$type]) ? $this->typeDict[$type] : 0);

        //验证是否为图片文件
        $imageInfo = getimagesize($imageUrl);
        $imagewidth = $imageInfo[0];
        $imageheight = $imageInfo[1];
        \think\Log::record(2);
        $replaceArr = [
            '{year}'     => date("Y"),
            '{mon}'      => date("m"),
            '{day}'      => date("d"),
            '{hour}'     => date("H"),
            '{min}'      => date("i"),
            '{sec}'      => date("s"),
            '{random}'   => Random::alnum(16),
            '{random32}' => Random::alnum(32),
            '{filename}' => $suffix ? substr($imgaeHeaderData['name'], 0, strripos($imgaeHeaderData['name'], '.')) : $imgaeHeaderData['name'],
            '{suffix}'   => $suffix,
            '{.suffix}'  => $suffix ? '.' . $suffix : '',
            '{filemd5}'  => md5_file($imageUrl),
        ];
        $savekey = $upload['savekey'];
        $savekey = str_replace(array_keys($replaceArr), array_values($replaceArr), $savekey);

        $uploadDir = substr($savekey, 0, strripos($savekey, '/') + 1);
        $fileName = substr($savekey, strripos($savekey, '/') + 1);

        file_put_contents(ROOT_PATH . '/public' . $uploadDir . $fileName, file_get_contents($imageUrl));
        \think\Log::record(2);
        // 将图片数据写入到数据库中
        $params = array(
            'admin_id'    => 0,
            'user_id'     => $userID,
            'filesize'    => $imgaeHeaderData['Content-Length'],
            'imagewidth'  => $imagewidth,
            'imageheight' => $imageheight,
            'imagetype'   => $suffix,
            'imageframes' => 0,
            'mimetype'    => $imgaeHeaderData['Content-Type'],
            'url'         => $uploadDir . $fileName,
            'uploadtime'  => time(),
            'storage'     => 'local',
            'sha1'        => '',
        );
        // $attachment = model("attachment");
        // $attachment->data(array_filter($params));
        Attachment::create(array_filter($params));
        \think\Log::record(2);
        return $uploadDir . $fileName;
    }

    /**
     * 检测图片是否符合要求
     * 
     * @param string $imageUrl  图片URL
     * @return bool
     */
    public function checkImage($imageUrl)
    {
        if (empty($imageUrl)) {
            // new Exception(__('Image url cannot empty, Line %s.', $line));
            return false;
        }

        // 获取上传配置项
        $upload = Config::get('upload');
        // 返回的数据格式如下：
        // Array ( [uploadurl] => ajax/upload [cdnurl] => [savekey] => /uploads/{year}{mon}{day}/{filemd5}{.suffix} [maxsize] => 10mb [mimetype] => jpg,png,bmp,jpeg,gif,zip,rar,xls,xlsx [multiple] => [bucket] => local [multipart] => Array ( ) )0.111007sShowPageTrace



        preg_match('/(\d+)(\w+)/', $upload['maxsize'], $matches);
        $type = strtolower($matches[2]);
        $size = (int) $upload['maxsize'] * pow(1024, isset($this->typeDict[$type]) ? $this->typeDict[$type] : 0);


        // 获取图片头信息
        $imageHeaderData = $this->getImageHeaderData($imageUrl);
        // 获取图片名称
        $imageHeaderData['name'] = $this->getImageName($imageUrl);

        $suffix = strtolower(pathinfo($imageHeaderData['name'], PATHINFO_EXTENSION));
        $suffix = $suffix && preg_match("/^[a-zA-Z0-9]+$/", $suffix) ? $suffix : 'file';

        $mimetypeArr = explode(',', strtolower($upload['mimetype']));
        $typeArr = explode('/', $imageHeaderData['Content-Type']);

        //禁止上传PHP和HTML文件
        if (in_array($imageHeaderData['Content-Type'], ['text/x-php', 'text/html']) || in_array($suffix, ['php', 'html', 'htm'])) {
            // new Exception(__('Image format not correct, Line %s.', $line));
            return false;
        }

        //验证文件后缀
        if (
            $upload['mimetype'] !== '*' && (!in_array($suffix, $mimetypeArr) || (stripos($typeArr[0] . '/', $upload['mimetype']) !== false && (!in_array($imageHeaderData['Content-Type'], $mimetypeArr) && !in_array($typeArr[0] . '/*', $mimetypeArr))))
        ) {
            // new Exception(__('Image format not correct, Line %s.', $line));
            return false;
        }

        //验证是否为图片文件
        if (in_array($imageHeaderData['Content-Type'], ['image/gif', 'image/jpg', 'image/jpeg', 'image/bmp', 'image/png', 'image/webp']) || in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'webp'])) {
            $imageInfo = getimagesize($imageUrl);
            if (!$imageInfo || !isset($imageInfo[0]) || !isset($imageInfo[1])) {
                // new Exception(__('invalid image, Line %s.', $line));
                return false;
            }
        }

        return true;
    }

    /**
     * 获取远程图片的头信息
     * 
     * @param string $imageUrl 图片URL
     * @return array
     */
    public function getImageHeaderData($imageUrl)
    {
        if (empty($imageUrl)) {
            new Exception('Image url cannot empty');
        }

        // 获取头部信息
        \think\Log::record('#imageUrl###' . $imageUrl);
        $headerData = get_headers($imageUrl, true);
        /*
        Array ( [0] => HTTP/1.1 200 OK [Server] => nginx/1.11.5 [Date] => Tue, 15 Sep 2020 03:04:01 GMT [Content-Type] => image/jpeg [Content-Length] => 44319 [Last-Modified] => Thu, 10 Sep 2020 10:10:14 GMT [Connection] => close [ETag] => "5f59fb86-ad1f" [Accept-Ranges] => bytes )0.098005sShowPageTrace
        */

        $rule = '/\s(\d+)\s/';
        preg_match($rule, $headerData[0], $code);
        if ($code[1] != 200) {
            new Exception('Get remote image fail');
        }

        $headerData['code'] = $code[1];

        return $headerData;
    }

    /**
     * 获取图片名称
     * 
     * @param string $imageUrl 图片URL
     * @return string 
     */
    public function getImageName($imageUrl)
    {
        if (empty($imageUrl)) {
            new Exception('Image url cannot empty');
        }

        $imageUrlArray = explode('/', $imageUrl);

        return end($imageUrlArray);
    }
}
